package com.masiyi.executor;

import com.masiyi.entity.Configuration;
import com.masiyi.entity.MappedStatement;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

/**
 * @Author masiyi
 * @Date 2023/11/10
 * @PackageName:com.masiyi.sqlSession
 * @ClassName: SqlSession
 * @Description: 放操作（查询）的地方
 * @Version 1.0
 */
@Data
public class SimpleSqlSession {
    private Configuration configuration;
    private SimpleExecutor simpleExecutor;

    public SimpleSqlSession(Configuration configuration) {
        this.configuration = configuration;
        this.simpleExecutor = new SimpleExecutor();
    }

    /**
     * 查询列表
     *
     * @param param
     * @param <E>
     * @return
     */
    public <E> List<E> selectList(MappedStatement mappedStatement, Object param) {

        //拿到 MappedStatement 对象，例如
        // <select id="findById" resultType="com.masiyi.entity.User" parameterType="java.lang.Integer">
        //        select * from user where id = #{id}
        //    </select>
        return simpleExecutor.query(configuration, mappedStatement, param);
    }


    public <T> T newProxyClass(Class<T> targetClass) {
        return (T) Proxy.newProxyInstance(SimpleSqlSession.class.getClassLoader(), new Class[]{targetClass}, new InvocationHandler() {

            /**
             *
             * @param proxy 调用该方法的代理实例
             *
             * @param method {@code Method}实例对应于在代理实例上调用的接口方法。{@code Method}对象的声明类将是该方法被声明的接口，
             *                             该接口可能是代理类继承该方法所通过的代理接口的超接口。
             *
             * @param args 一个对象数组，包含在代理实例上的方法调用中传递的参数值，或者如果接口方法不接受参数，则{@code null}。
             *             基本类型的参数被包装在适当的基本包装器类的实例中，例如{@code java.lang。Integer}或{@code java.lang.Boolean}。
             *
             * @return 方法的返回值
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) {
                //拿到statementId
                String statementId = method.getDeclaringClass().getName() + "." + method.getName();

                MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);

                //todo 添加其他的增删改查方法,渲染传递的参数值
                return selectList(mappedStatement, args == null ? null : args[0]);
            }
        });

    }


    /**
     * 关闭资源
     */
    public void close() {
        simpleExecutor.close();
    }
}